#!/usr/bin/env bash
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# Function :CentOS7.X  批量（drds服务器组内） 执行 命令
# Platform :RedHatEL7.x Based Platform
# Version  :1.02
# Date     :2022-05-04
# Author   :mugoLH
# Contact  :houxiaoshuai@baidu.com & hxsaj@126.com
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
#  变量列表 List of common variables
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
#  获取主机名列的源文件
DEFAULT_HOST_FILE=/etc/hosts
#  默认主机组关键字（默认留空）
DEFAULT_HOST_KEY=""
HOST_KEY=""

#  函数列表 Function list
# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
info_p(){  printf "\e[1;35;40m%-8s %-30s %-24s %-2s %-2s\e[0m\n" "$(date '+%H:%M:%S')" "${1}" "${2}" "${3}" "${4}" >&1 ;}
error_p(){ printf "\e[1;35;40m%-8s\e[0m %-12s %-1s\n\e[0m"      "$(date '+%H:%M:%S')" "${1}" "${2}"  >&1 ;}


help_f(){
    echo -e "说明：\n    pl2 \"{linux 命令}\" 实现批量执行远程命令；"
    echo -e "\n示例：\n"
    echo -e "  pl uname -a                             :在默认服务器组上执行 uname -a 命令(注：pl2 后的命令最好用\"uname -a\"限制起来，避免命令逃逸)"
    echo -e "  pl -f ./host.list uname -a              :从./host.list主机清单文件获取所有服务器批量串行执行 uname -a 命令"
    echo -e "  pl -g zookeeper uname -a                :从默认主机清单文件中，获取 zookeeper 角色服务器上执行 uname -a 命令"
    echo -e "  pl -g zookeeper -f ./host.list uname -a :从./host.list主机清单文件获取 zookeeper 关键字的服务器批量串行执行 uname -a 命令"
    echo -e "  pl -i {ip} -i {ip} ......               :每个-i后面跟一个ip，支持直接ip远程执行命令"
    echo -e "\n 可用的选项如下（也可不加选项默认执行所有默认主机）："
    echo -e "    -f or --file  指定IP和主机名文件，可以为/etc/hosts"
    echo -e "    -g or --group 指定服务器主机名关键字，也就是主机组，指定在指定的主机组上执行命令"
    echo -e "\n主机名清单文件结构如下：

#  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
#      IP(必要)   | 主机名(必要) | 角色/说明/部署组件(可选) | 地域/机房/局点(可选) | 用户名(可选) |  端口(可选)  |
#  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
192.168.123.29    drdsmp01        zookeeper,xdb              北京可用区3            root          22
192.168.123.111   drdsmp02        zookeeper,xdb              北京可用区3            root          22
192.168.123.79    drdsnode01      zookeeper                  北京可用区3            root          22
192.168.123.106   drdsnode02

"
}

#  IP检查合法性
check_ip() {
    IP=$1
    if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        FIELD1=$(echo $IP|cut -d. -f1)
        FIELD2=$(echo $IP|cut -d. -f2)
        FIELD3=$(echo $IP|cut -d. -f3)
        FIELD4=$(echo $IP|cut -d. -f4)
        if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
            echo "ok"
        else
            echo "no"
        fi
    else
        echo "error"
    fi
}

ctl_ops(){
    #  检查带入的参数是否为空，若为空则打印提示信息
    if [[ $# -gt 0 ]];then
    #  如果未指定主机组，则获取主机文件中所有主机
        if [[ ${#HOST_IP[@]} -eq 0 ]];then
            if [[ -z ${HOST_KEY} ]];then
            #  获取主机 IP 列表
                IPs=($(grep -Ev "localhost|^#|127.0.0.1" ${HOST_FILE} | awk '{print$1}' | sort | uniq ))
            #  指定主机组，则获取主机文件中指定的主机 IP 列表
            elif [[ -n ${HOST_KEY} ]]; then
                IPs=($(grep -Ev "localhost|^#" ${HOST_FILE} | grep ${HOST_KEY}| awk '{print$1}' | sort | uniq ))
            fi
            #  遍历主机执行命令
            for i in ${IPs[@]};do
                if [ $(grep -Ev "^#" ${HOST_FILE} | grep -w ${i} | awk '{print NF}'|sort|uniq) -eq 6 ];then
                    Host_User=$(grep -Ev "^#" ${HOST_FILE} | grep -w ${i} | awk '{print$5}' | sort | uniq)
                    Host_Port=$(grep -Ev "^#" ${HOST_FILE} | grep -w ${i} | awk '{print$6}' | sort | uniq)
                    Host_Name=$(grep -Ev "^#" ${HOST_FILE} | grep -w ${i} | awk '{print$2}' | sort | uniq)
                    info_p "节点:${Host_Name}" "IP:${i}" "# $@ "
                    #  远程执行，如果对执行错误有要求，可删除下面命令行break前的#号
                    ssh -p ${Host_Port} ${Host_User}@${i} "$@" #|| break 1
                    echo ""
                else
                    Host_Name=$(grep -Ev "^#" ${HOST_FILE} | grep -w ${i} | awk '{print$2}' | sort | uniq)
                    info_p "节点:${Host_Name}" "IP:${i}" "# $@ "
                    ssh ${i} "$@" #|| break 1
                fi
            done
        else
            IPs=(${HOST_IP[@]})
            #  遍历主机执行命令
            for i in ${IPs[@]};do
                #  远程执行，如果对执行错误有要求，可删除下面命令行break前的#号
                info_p "节点:None" "IP:${i}" "# $@ "
                ssh ${i} "$@" #|| break 1
            done
        fi
    else
        error_p  "[ NOTICE ]:" "未指定执行命令，请检查！"
        return 0
    fi
}


# 如果参数为空，则退出
if [ $# -gt 0 ];then
    #  获取主机组关键字
    while [ -n "$1" ]; do
        case $1 in
            -g | --group)
                HOST_KEY="${2}"
                shift 2
                ;;
            -f | --file )
                HOST_FILE="${2}"
                shift 2
                ;;
            -h | --help )
                help_f
                exit
                ;;
            -i | --ip )
                HOST_IP[${#HOST_IP[@]}]="${2}"
                shift 2
                ;;
            *)
                break
                ;;
        esac
    done
    #  没输入关键字，则使用默认关键字
    [[ -z ${HOST_KEY} ]]    && HOST_KEY=${DEFAULT_HOST_KEY}
    # 如果有指定IP，则优先使用IP，否则使用指定的文件获取IP
    if [[ ${#HOST_IP[@]} -eq 0 ]];then
        #  没有指定主机清单文件，则使用默认主机清单文件
        [[ ! -f ${HOST_FILE} ]] && HOST_FILE=${DEFAULT_HOST_FILE}
    fi
    #  远程执行命令
    ctl_ops "$@"
fi

